<template>
  <div :style="{ ...coreStyle.marginSame(8) }">
    <a-card>
      <a-row :gutter="12">
        <a-col :span="12">
          <a-card :bordered="false" :bodyStyle="{ border: '1px dashed #0000000f' }">
            <a-row :gutter="8">
              <a-col :span="12">
                <Dict v-model="dbTableGrouping" dictKey="dataDbTableGroupingSearch" formItemName="dbTableGrouping" @change="dbTableGroupingDictSelectChange" />
              </a-col>
              <a-col :span="12">
                <a-select v-model:value="dbTableId" optionFilterProp="title" show-search allowClear placeholder="请选择数据库表" :style="{ ...coreStyle.width('100%') }" @change="dbTableListDataSelectChange">
                  <a-select-option v-for="item in dbTableListDataSet" :value="item.id" :key="item.id" :title="item.tableNameAnnotation">
                    {{ item.tableNameAnnotation }}
                  </a-select-option>
                </a-select>
              </a-col>
              <a-col :span="5" :style="{ ...coreStyle.marginTop(8) }">
                <a-input v-model:value="dbTableVOModel.dbTablePrefix" placeholder="数据库表前缀" />
              </a-col>
              <a-col :span="7" :style="{ ...coreStyle.marginTop(8) }">
                <a-input v-model:value="dbTableVOModel.tableNameAnnotation" placeholder="表名" />
              </a-col>
              <a-col :span="12" :style="{ ...coreStyle.marginTop(8) }">
                <a-button :loading="dbTableVOSaveSubmitting" type="dashed" :style="{ ...coreStyle.antBtnSave }" @click="dbTableVOSave">
                  <CoreIcon :icon="coreStyle.antBtnIconSave" :size="14" />
                  保存
                </a-button>
                <a-space :style="{ ...coreStyle.floatRight }">
                  <a-button type="dashed" :style="{ 'color': '#f759ab' }" @click="generateField">
                    <CoreIcon icon="whh:lightning" color="#ed6f6f" :size="14" />
                    生成字段
                  </a-button>
                  <a-button type="dashed" :style="{ 'color': '#9254de' }" @click="generateSql">
                    <CoreIcon icon="whh:lightning" color="#ed6f6f" :size="14" />
                    生成SQL
                  </a-button>
                </a-space>
              </a-col>
              <a-col :span="24" :style="{ ...coreStyle.marginTop(8) }">
                <a-textarea v-model:value="dbTableFieldListString" :rows="3" placeholder="由字段名称列表字符串生成字段" />
              </a-col>
            </a-row>
            <div :style="{ ...coreStyle.height(536), ...coreStyle.marginTop(8) }">
              <ScrollContainer>
                <a-row v-for="(item, index) in dbTableFieldList" :key="index" :style="{ ...coreStyle.marginTop(8) }">
                  <a-col :span="11">
                    <a-input v-model:value="dbTableFieldList[index].fieldName" placeholder="字段名称" />
                  </a-col>
                  <a-col :span="13">
                    <a-space :style="{ ...coreStyle.marginLeft(8) }">
                      <a-radio-group v-model:value="dbTableFieldList[index].dataType">
                        <a-radio-button value="varchar">String</a-radio-button>
                        <a-radio-button value="bigint">Long</a-radio-button>
                      </a-radio-group>
                      <a-radio-group v-model:value="dbTableFieldList[index].isempty">
                        <a-radio-button value="y">空</a-radio-button>
                        <a-radio-button value="n">非空</a-radio-button>
                      </a-radio-group>
                    </a-space>
                    <a-space :style="{ ...coreStyle.floatRight, ...coreStyle.marginRight(12) }">
                      <a-button type="dashed" shape="circle" @click="dbTableFieldListAddRow(index)">
                        <CoreIcon icon="carbon:add-alt" color="#1890FF" :size="14" />
                      </a-button>
                      <a-button type="dashed" shape="circle" danger @click="dbTableFieldListDeleteRow(index)">
                        <CoreIcon icon="jam:delete" :size="14" />
                      </a-button>
                    </a-space>
                  </a-col>
                </a-row>
              </ScrollContainer>
            </div>
          </a-card>
        </a-col>
        <a-col :span="12">
          <a-card :bordered="false" :bodyStyle="{ border: '1px dashed #0000000f' }">
            <CodeEditorSql ref="sqlCodeEditorRef" langType="sql" :docStr="sqlStr" :height="sqlEditorHeight" v-if="sqlEditorVisible" />
          </a-card>
        </a-col>
      </a-row>
    </a-card>
  </div>
</template>

<script lang="ts">
import { Options, Vue } from 'vue-class-component'
import { mapStores } from 'pinia'
import { useCoreToolStore } from '/@/store/modules/cn/core/tool/coreToolStore'
import type { Res } from '/@/tool/Res'
import type { Param } from '/@/tool/Param'

import pinyin from 'js-pinyin'

import { useDbTableStore } from '/@/store/modules/cn/core/data/dbTableStore'

import type { DbTable } from '/@/model/cn/core/data/eo/DbTable'
import { toDbTable } from '/@/model/cn/core/data/eo/DbTable'

import type { DbTableQO } from '/@/model/cn/core/data/qo/DbTableQO'
import { toDbTableQO } from '/@/model/cn/core/data/qo/DbTableQO'

import type { DbTableVO } from '/@/model/cn/core/data/vo/DbTableVO'
import { toDbTableVO } from '/@/model/cn/core/data/vo/DbTableVO'

import { useDbTableFieldStore } from '/@/store/modules/cn/core/data/dbTableFieldStore'

import type { DbTableField } from '/@/model/cn/core/data/eo/DbTableField'
import { toDbTableField } from '/@/model/cn/core/data/eo/DbTableField'

import type { DbTableFieldQO } from '/@/model/cn/core/data/qo/DbTableFieldQO'
import { toDbTableFieldQO } from '/@/model/cn/core/data/qo/DbTableFieldQO'

import type { DbTableFieldVO } from '/@/model/cn/core/data/vo/DbTableFieldVO'
import { toDbTableFieldVO } from '/@/model/cn/core/data/vo/DbTableFieldVO'

@Options({
  name: 'CoreDbTable',
  components: {
  },
  computed: {
    ...mapStores(useCoreToolStore, useDbTableStore, useDbTableFieldStore),
  },
})
export default class CoreDbTable extends Vue {

  dbTableGrouping: string | null = null

  dbTableId: string | null = null

  dbTableListDataSet: Array<DbTable> = []

  dbTableVOModel: DbTableVO = toDbTableVO()

  dbTableFieldListString: string | null = null

  dbTableFieldList: Array<DbTableField> = []

  dbTableGroupingDictSelectChange(value) {
    this.dbTableListDataSet = []
    this.dbTableId = null
    this.dbTableVOModel = toDbTableVO()
    this.dbTableVOModel.dbTableGrouping = value
    this.dbTableFieldListString = null
    this.dbTableFieldList = []
    this.dbTableFieldList.push({ fieldName: null, dataType: 'varchar', isempty: 'y' } as DbTableField)
    if (value) {
      this.dbTableStore.query(this.$toParam<DbTableQO>(this.$toSearch({ dbTableGrouping: value }) as DbTableQO)).then((res: Res<DbTable>) => {
        if (res.succ) {
          this.dbTableListDataSet = [ ...res.data ]
        } else {
          this.$message.error(res.msg, 6)
        }
      }).catch(err => {
      })
    }
  }

  dbTableListDataSelectChange(value) {
    this.dbTableFieldListString = null
    this.dbTableFieldList = []
    this.dbTableFieldList.push({ fieldName: null, dataType: 'varchar', isempty: 'y' } as DbTableField)
    if (value) {
      this.dbTableStore.pk(this.$toParam<DbTableQO>({ id: value } as DbTableQO)).then((res: Res<DbTable>) => {
        if (res.succ) {
          this.dbTableVOModel = { ...res.data[0] }
        } else {
          this.$message.error(res.msg, 6)
        }
      }).catch(err => {
      })
      this.dbTableFieldStore.query(this.$toParam<DbTableFieldQO>({ fkid: value, weightOrderAsc: 'y' } as DbTableFieldQO)).then((res: Res<DbTableField>) => {
        if (res.succ) {
          if (res.data.length !== 0) {
            this.dbTableFieldList = [ ...res.data ]
          }
        } else {
          this.$message.error(res.msg, 6)
        }
      }).catch(err => {
      })
    } else {
      this.dbTableVOModel = toDbTableVO()
      this.dbTableVOModel.dbTableGrouping = this.dbTableGrouping
    }
  }

  dbTableFieldListAddRow(index) {
    this.dbTableFieldList.splice(index + 1, 0, { fieldName: null, dataType: 'varchar', isempty: 'y' } as DbTableField)
  }

  dbTableFieldListDeleteRow(index) {
    this.dbTableFieldList.splice(index, 1)
    if (this.dbTableFieldList.length === 0) {
      this.dbTableFieldList.push({ fieldName: null, dataType: 'varchar', isempty: 'y' } as DbTableField)
    }
  }

  dbTableVOSaveSubmitting: boolean = false

  dbTableVOSave() {
    this.dbTableVOSaveSubmitting = true
    if (!this.dbTableVOModel.dbTableGrouping) {
      this.$message.error('未选择分组！', 6)
      setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
      return
    }
    if (!this.dbTableVOModel.tableNameAnnotation) {
      this.$message.error('表名不能为空！', 6)
      setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
      return
    }
    if (this.dbTableVOModel.id) {
      this.dbTableVOModel.dbTableFieldList = this.dbTableFieldList
      this.dbTableStore.update(this.$toParam<DbTableVO>(this.dbTableVOModel)).then((res: Res<DbTableVO>) => {
        if (res.succ) {
          this.$message.success(res.msg, 3)
          this.dbTableVOSaveSubmitting = false
        } else {
          this.$message.error(res.msg, 6)
          setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
        }
      }).catch(err => {
        setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
      })
    } else {
      this.dbTableVOModel.dbTableFieldList = this.dbTableFieldList
      this.dbTableStore.save(this.$toParam<DbTableVO>(this.dbTableVOModel)).then((res: Res<DbTableVO>) => {
        if (res.succ) {
          this.$message.success(res.msg, 3)
          this.dbTableVOModel.id = res.data[0].id
          this.dbTableVOSaveSubmitting = false
        } else {
          this.$message.error(res.msg, 6)
          setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
        }
      }).catch(err => {
        setTimeout(() => { this.dbTableVOSaveSubmitting = false }, 3000)
      })
    }
  }

  generateField() {
    if (this.dbTableFieldListString) {
      this.dbTableFieldListString.split('\n').forEach((eo: string) => {
        if (eo) {
          this.dbTableFieldList.push({ fieldName: eo, dataType: 'varchar', isempty: 'y' } as DbTableField)
        }
      })
    }
  }

  sqlStr: string = ''

  sqlEditorHeight: string = '700px'

  sqlEditorVisible: boolean = true

  generateSql() {
    let tableName: string = ''
    if (this.dbTableVOModel.tableNameAnnotation) {
      if (this.dbTableVOModel.dbTablePrefix) {
        // tableName = this.dbTableVOModel.dbTablePrefix + this.getCaseUnderlineByHump(pinyin.getFullChars(this.dbTableVOModel.tableNameAnnotation))
        tableName = this.dbTableVOModel.dbTablePrefix + this.getCaseUnderlineByChineseCharacter(this.dbTableVOModel.tableNameAnnotation)
      } else {
        tableName = this.getCaseUnderlineByChineseCharacter(this.dbTableVOModel.tableNameAnnotation)
      }
    }
    let dbTableFieldListStr: string = ''
    this.dbTableFieldList.forEach((eo: DbTableField) => {
      let sqlRowStr: string = ''
      if (eo.fieldName) {
        // let fieldNameStr: string = this.getCaseUnderlineByHump(pinyin.getFullChars(eo.fieldName))
        let fieldNameStr: string = this.getCaseUnderlineByChineseCharacter(eo.fieldName)
        sqlRowStr = '  ' + fieldNameStr + this.getBlankStr(30 - fieldNameStr.length) + ('varchar' === eo.dataType ? '  varchar(255)    ' : 'bigint' === eo.dataType ? '  bigint(20)      ' : ' ') + ('y' === eo.isempty ? '    null' : 'n' === eo.isempty ? 'not null' : ' ') + ' comment \'' + eo.fieldName + '\','
      }
      dbTableFieldListStr = dbTableFieldListStr + sqlRowStr + '\n'
    })
    let sqlStr: string = 
`/*============================================================================================*/
/* Name:<${this.dbTableVOModel.tableNameAnnotation}> Table: ${tableName}   */
/*============================================================================================*/
drop table if exists ${tableName};
create table ${tableName} (
  ID                              varchar(36)     not null comment 'Id',
${dbTableFieldListStr}  primary key ( ID )
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='${this.dbTableVOModel.tableNameAnnotation}';
`
    // this.$refs.sqlCodeEditorRef.editorView.dispatch({
    //   changes: {from: 0, to: this.$refs.sqlCodeEditorRef.editorView.state.doc.length, insert: ''}
    // })
    // this.$refs.sqlCodeEditorRef.editorView.dispatch({
    //   changes: {from: 0, insert: sqlStr}
    // })
    this.$refs.sqlCodeEditorRef.editorView.dispatch({
      changes: {from: 0, to: this.$refs.sqlCodeEditorRef.editorView.state.doc.length, insert: sqlStr}
    })
  }

  getCaseUnderlineByHump(str: string) {
    let rStr: string = ''
    if (str) {
      [...str].forEach((eo: string) => {
        if (/[A-Z]/.test(eo)) {
          if (rStr.length !== 0) {
            rStr = rStr + '_'
          }
          rStr = rStr + eo
        } else {
          rStr = rStr + eo
        }
      })
    }
    return rStr.toUpperCase()
  }

  getCaseUnderlineByChineseCharacter(str: string) {
    let chineseCharacterStr: string = ''
    let letterStr: string = ''
    if (str) {
      [...str].forEach((eo: string) => {
        let ucode: number = eo.charCodeAt(0)
        if (ucode >= 0x4e00 && ucode <= 0x9fff) {
          let pinyinStr: string = pinyin.getFullChars(eo)
          if (pinyinStr.length === 1) {
            if (chineseCharacterStr.length !== 0) {
              chineseCharacterStr = chineseCharacterStr + pinyinStr.toLowerCase()
            } else {
              chineseCharacterStr = chineseCharacterStr + pinyinStr + pinyinStr.toLowerCase()
            }
          } else {
            chineseCharacterStr = chineseCharacterStr + pinyinStr
          }
        } else {
          if (/[a-zA-Z0-9]/.test(eo)) {
            letterStr = letterStr + eo
          }
        }
      })
    }
    let humpStr: string = chineseCharacterStr
    if (letterStr) {
      if (letterStr.length === 1) {
        humpStr = humpStr + letterStr.toLowerCase()
      } else {
        humpStr = humpStr + letterStr.substring(0, 1).toUpperCase() + letterStr.substring(1).toLowerCase()
      }
    }
    let rStr: string = ''
    if (humpStr) {
      [...humpStr].forEach((eo: string) => {
        if (/[A-Z]/.test(eo)) {
          if (rStr.length !== 0) {
            rStr = rStr + '_'
          }
          rStr = rStr + eo
        } else {
          rStr = rStr + eo
        }
      })
    }
    return rStr.toUpperCase()
  }

  getBlankStr(len: number) {
    let rBlankStr: string = ''
    for (let i = 0; i < len; i++) {
      rBlankStr = rBlankStr + ' '
    }
    return rBlankStr
  }

  mounted() {
    this.dbTableFieldList.push({ fieldName: null, dataType: 'varchar', isempty: 'y' } as DbTableField)
  }

  beforeUnmount() {
    this.$refs.sqlCodeEditorRef.editorView.destroy()
  }

}
</script>

<style scoped lang="less">

</style>
